#include "soundout.h"

void SoundOutThread::run()
{
  connect(m_pushTimer, SIGNAL(timeout()), SLOT(pushTimerExpired()));
}

void SoundOutThread::setRate(double rate)
{
  if (isRunning()) return;                       //Maybe abort() instead ?
  this->m_rate = rate;
}

void SoundOutThread::setOutputDevice(const QAudioDeviceInfo& device)
{
  if (isRunning()) return;
  this->m_device = device;
}

//--------------------------------------------------------------------------
// Private function pushTimerExpired()
//--------------------------------------------------------------------------
void SoundOutThread::pushTimerExpired()
{
  // Writes data from a buffer (pointed to by m_txData) into m_output,
  // which amounts to writing directly to the soundcard.

  // Space available in the output buffer is limited to
  // m_audioOutput->bytesFree().  If this number is 0, the function
  // simply returns.  Otherwise, chunks of size m_audioOutput->periodSize()
  // are written into the QIODevice pointed at by m_output.

  // I think m_audioOutput->periodSize() must be the low-level buffer
  // size for the soundcard.


  if (m_audioOutput && (m_audioOutput->state() != QAudio::StoppedState)) {
    int chunks = m_audioOutput->bytesFree()/m_audioOutput->periodSize();

    while (chunks) {
      const qint64 len = m_audioOutput->periodSize();
      if (len) {
        if(m_txMute) {
          m_output->write(m_zeros.data(), len);

        } else {
          m_output->write(m_txData, len);
        }
        m_txData += len;
        m_samplesWritten += len/2;
      }
      if (len != m_audioOutput->periodSize())
        break;
      --chunks;
    }
    if(m_samplesWritten >= m_npts) {
      m_audioOutput->stop();
      m_pushTimer->stop();
    }
  }
}

//--------------------------------------------------------------------------
// Private function txMute()
//--------------------------------------------------------------------------
void SoundOutThread::txMute()
{
  m_txMute = !m_txMute;
}

//--------------------------------------------------------------------------
// Private function play()
//--------------------------------------------------------------------------
void SoundOutThread::play(qint16* wave, qint64 npts)
{
  m_txData = (char *)wave;
  m_npts=npts;
  m_txMute=false;
  m_samplesWritten=0;

  m_format.setFrequency(m_rate);
  m_format.setChannels(1);
  m_format.setSampleSize(16);
  m_format.setCodec("audio/pcm");
  m_format.setByteOrder(QAudioFormat::LittleEndian);
  m_format.setSampleType(QAudioFormat::SignedInt);

  delete m_audioOutput;
  m_audioOutput = 0;
  m_audioOutput = new QAudioOutput(m_device, m_format, this);

  //  connect(m_audioOutput, SIGNAL(notify()), SLOT(notified()));

  m_output = m_audioOutput->start();
  m_pushTimer->start(20);
}

//--------------------------------------------------------------------------
// Private function abort()
//--------------------------------------------------------------------------
void SoundOutThread::abort()
{
  m_pushTimer->stop();
  m_audioOutput->stop();
}
